package info.galudisu;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Usage:
 * <li>String msg = Ansi.Red.and(Ansi.BgYellow).format("Hello %s", name)
 * <li>String msg = Ansi.Blink.colorize("BOOM!") Or, if you are adverse to that, you can use the
 *     constants directly:
 * <li>String msg = new Ansi(Ansi.ITALIC, Ansi.GREEN).format("Green money") Or, even:
 * <li>String msg = Ansi.BLUE + "scientific" NOTE: Nothing stops you from combining multiple FG
 *     colors or BG colors, but only the last one will display.
 *
 * @author dain
 */
public final class Ansi {

  // Color code strings from:
  // http://www.topmudsites.com/forums/mud-coding/413-java-ansi.html
  public static final String SANE = "\u001B[0m";

  public static final String HIGH_INTENSITY = "\u001B[1m";
  public static final String LOW_INTENSITY = "\u001B[2m";

  public static final String ITALIC = "\u001B[3m";
  public static final String UNDERLINE = "\u001B[4m";
  public static final String BLINK = "\u001B[5m";
  public static final String RAPID_BLINK = "\u001B[6m";
  public static final String REVERSE_VIDEO = "\u001B[7m";
  public static final String INVISIBLE_TEXT = "\u001B[8m";

  public static final String BLACK = "\u001B[30m";
  public static final String RED = "\u001B[31m";
  public static final String GREEN = "\u001B[32m";
  public static final String YELLOW = "\u001B[33m";
  public static final String BLUE = "\u001B[34m";
  public static final String MAGENTA = "\u001B[35m";
  public static final String CYAN = "\u001B[36m";
  public static final String WHITE = "\u001B[37m";

  public static final String BACKGROUND_BLACK = "\u001B[40m";
  public static final String BACKGROUND_RED = "\u001B[41m";
  public static final String BACKGROUND_GREEN = "\u001B[42m";
  public static final String BACKGROUND_YELLOW = "\u001B[43m";
  public static final String BACKGROUND_BLUE = "\u001B[44m";
  public static final String BACKGROUND_MAGENTA = "\u001B[45m";
  public static final String BACKGROUND_CYAN = "\u001B[46m";
  public static final String BACKGROUND_WHITE = "\u001B[47m";

  public static final Ansi HighIntensity = new Ansi(HIGH_INTENSITY);
  public static final Ansi Bold = HighIntensity;
  public static final Ansi LowIntensity = new Ansi(LOW_INTENSITY);
  public static final Ansi Normal = LowIntensity;

  public static final Ansi Italic = new Ansi(ITALIC);
  public static final Ansi Underline = new Ansi(UNDERLINE);
  public static final Ansi Blink = new Ansi(BLINK);
  public static final Ansi RapidBlink = new Ansi(RAPID_BLINK);

  public static final Ansi Black = new Ansi(BLACK);
  public static final Ansi Red = new Ansi(RED);
  public static final Ansi Green = new Ansi(GREEN);
  public static final Ansi Yellow = new Ansi(YELLOW);
  public static final Ansi Blue = new Ansi(BLUE);
  public static final Ansi Magenta = new Ansi(MAGENTA);
  public static final Ansi Cyan = new Ansi(CYAN);
  public static final Ansi White = new Ansi(WHITE);

  public static final Ansi BgBlack = new Ansi(BACKGROUND_BLACK);
  public static final Ansi BgRed = new Ansi(BACKGROUND_RED);
  public static final Ansi BgGreen = new Ansi(BACKGROUND_GREEN);
  public static final Ansi BgYellow = new Ansi(BACKGROUND_YELLOW);
  public static final Ansi BgBlue = new Ansi(BACKGROUND_BLUE);
  public static final Ansi BgMagenta = new Ansi(BACKGROUND_MAGENTA);
  public static final Ansi BgCyan = new Ansi(BACKGROUND_CYAN);
  public static final Ansi BgWhite = new Ansi(BACKGROUND_WHITE);

  private final String[] codes;
  private final String codesStr;

  public Ansi(String... codes) {
    this.codes = codes;
    final StringBuilder cs = new StringBuilder();
    for (String code : codes) {
      cs.append(code);
    }
    this.codesStr = cs.toString();
  }

  public Ansi and(Ansi other) {
    List<String> both = new ArrayList<>();
    Collections.addAll(both, codes);
    Collections.addAll(both, other.codes);
    return new Ansi(both.toArray(new String[] {}));
  }

  public String colorize(String original) {
    return codesStr + original + SANE;
  }

  public String format(String template, Object... args) {
    return colorize(String.format(template, args));
  }
}
